//
// Created by daybeha on 2022/7/12.
//

#ifndef SUPERGLUE_LOOPCLOSE_H
#define SUPERGLUE_LOOPCLOSE_H

#include <Python.h>
#include "numpy/arrayobject.h"

#include <opencv2/opencv.hpp>
#include <string>

using namespace std;
using namespace cv;

class loopclose {
public:
    const char * python_modle= "sg_match";
    const char * python_func = "compute_score";
    PyObject *pName, *pModule, *pFunc, *pDict;

    /// 将C++的CV::Mat类型装换为python的numpy类型
    PyObject* Mat2Numpy(cv::Mat& img){
        _import_array();

        int r = img.rows;
        int c = img.cols;
        int ch = img.channels();
        // total number of elements (here it's an RGB image of size 640x480)
        int nElem = r * c * ch;

        // 创建数组类型，保存上面读到的图片
        // create an array of apropriate datatype
        uchar* m = new uchar[nElem];
        // copy the data from the cv::Mat object into the array
        std::memcpy(m, img.data, nElem * sizeof(uchar));

        // the dimensions of the matrix
        PyObject* mat;
        cout << "mdim : " << endl;
        if(ch == 1){
            npy_intp mdim[2] = {r, c};
            cout << mdim[0] << ", " << mdim[1] << ", "<< mdim[2] <<endl;
            // 将cv::Mat 转为 numpy.array 类型 convert the cv::Mat to numpy.array
            mat = PyArray_SimpleNewFromData(2, mdim, NPY_UINT8, (void*) m);
        }else{
            npy_intp mdim[3] = {r, c, ch};
            cout << mdim[0] << ", " << mdim[1] << ", "<< mdim[2] <<endl;
            mat = PyArray_SimpleNewFromData(3, mdim, NPY_UINT8, (void*) m);
        }


        delete[] m;
        return mat;
    }

    float compute_match_score(cv::Mat& img0, cv::Mat& img1){
        float score=-1;

//        //文献[3]中在此处需要调用PyGILState_Check()检测当前线程是否拥有GIL，
//        //但我的环境并不能编译PyGILState_Check，但我实测没有PyGILState_Check也OK.
//        PyGILState_STATE gstate;
//        gstate = PyGILState_Ensure();   //如果没有GIL，则申请获取GIL
//        Py_BEGIN_ALLOW_THREADS;
//            Py_BLOCK_THREADS;

//        _import_array();

        PyObject *mat0 = Mat2Numpy(img0);
        PyObject *mat1 = Mat2Numpy(img1);

        PyObject *pArgs = PyTuple_New(2);     // 必须先创建Tuple
        PyTuple_SetItem(pArgs, 0, mat0);
        PyTuple_SetItem(pArgs, 1, mat1);

//        PyObject *pArgs = PyTuple_New(1);     // 必须先创建Tuple
//        PyTuple_SetItem(pArgs, 0, PyLong_FromLong(5));

        PyObject *result = PyEval_CallObject(pFunc, pArgs);

        if (result != NULL) {
            score = PyFloat_AsDouble(result);
            printf("Result of call: %f\n",score);
            Py_DECREF(result);
        } else {
            cerr << "result Null" << endl;
        }

        // 释放引用 decrement the object references
        Py_XDECREF(mat0);
        Py_XDECREF(mat1);
        Py_XDECREF(result);
        Py_XDECREF(pArgs);

//            Py_UNBLOCK_THREADS;
//        Py_END_ALLOW_THREADS;
//        PyGILState_Release(gstate);    //释放当前线程的GIL

        return score;
    }

    bool loadPython();
    void run();

};


#endif //SUPERGLUE_LOOPCLOSE_H
